This tutorial demonstrates some key mapping functionality in R.
tmapThe R package tmap provides an easy way of creating “thematic” maps.
library(tidyverse)
library(tmap)
# A great intro document
# vignette("tmap-getstarted")
#Get tips
tmap_tip()
## An manual legend can be created with tm_add_legend.
##
## data(metro)
## tm_shape(metro) +
## tm_symbols(col = "pop2020", size = "pop2020", legend.col.show = FALSE, legend.size.show = FALSE) +
## tm_add_legend(type = "symbol", border.col = "grey40",
## col = tmaptools::get_brewer_pal("YlOrRd", 4, plot = FALSE),
## size = sqrt(seq(1:4) / 4),
## labels = c("0 to 10 mln", "10 to 20 mln", "20 to 30 mln", "30 to 40 mln"),
## title = "Population in 2020")
There are a number of datasets provided within the tmap package. We will use the “world” data.
data("World")
Inspect the output from the following code.
str(World)
class(World)
# Specifies shape information for each row
World$geometry
The functions tm_shape and tm_polygons are used to create and colour a map.
# Create a blank map
tm_shape(World) + tm_polygons()
# Create a map, colour coded by life expectancy
tm_shape(World) + tm_polygons("life_exp")
Plots can be static or interactive
# Change mode to interactive "view"
tmap_mode("view")
tm_shape(World) + tm_polygons("life_exp")
#To toggle between the modes
ttm()
#To switch back to static mode
tmap_mode("plot")
You can merge your own data with World and display it on the graph. Here, we use random numbers to demonstrate the concept.
World$rand <- rnorm(dim(World)[1],0,1)
tm_shape(World) + tm_polygons("rand", midpoint = NA)
Multiple layers of data can be added to plots.
data(World, metro, rivers, land)
Explore each part of the code separately to see its function.
tm_shape(land) +
tm_raster("elevation", palette = terrain.colors(10))
tm_shape(World) +
tm_borders("white", lwd = .5) +
tm_text("iso_a3", size = "AREA")
tm_shape(metro) +
tm_symbols(col = "red", size = "pop2020", scale = .5)
These commands can be combined as follows. Notice how the layers get overlaid.
tm_shape(land) +
tm_raster("elevation", palette = terrain.colors(10)) +
tm_shape(World) +
tm_borders("white", lwd = .5) +
tm_text("iso_a3", size = "AREA") +
tm_shape(metro) +
tm_symbols(col = "red", size = "pop2020", scale = .5) +
tm_legend(show = FALSE)
Colours, titles and margins etc can be customised.
Options can also be set locally using tm_layout.
tm_shape(World) + tm_polygons("life_exp") +
tm_layout(bg.color = "skyblue", inner.margins = c(0, .02, .02, .02))
Options can also be set globally using tmap_options and tmap_style.
tmap_options(bg.color = "black", legend.text.color = "white")
tm_shape(World) + tm_polygons("life_exp")
tmap_style("classic")
tm_shape(World) + tm_polygons("life_exp")
tmap_style("watercolor")
tm <- tm_shape(World) + tm_polygons("life_exp")
## save an image ("plot" mode)
tmap_save(tm, filename = "world_map.png")
## save as stand-alone HTML file ("view" mode)
tmap_save(tm, filename = "world_map.html")
Start from this plot:
tmap_mode("plot")
tm_shape(World) + tm_polygons("life_exp")
tm_layout to:tm_polygons to change the colour paletterm(list=ls())
ggmapThe package ggmap uses the conventions of ggplot2 and applies them to mapping.
Load the package.
library(ggmap)
In ggmap (and many other mapping packages), there are two step: 1) get the map data and 2) create the plot. The function qmap perfoms both steps at once.
The function qmap (short for quick map) allows you to create a map very quickly.
qmap(location="auckland")
We can be even more specific with our location. The location string can be anything that you would type into google.
qmap(location="AUT university", zoom=17, maptype = "satellite")
We will now add a marker our current location. First we will get the coordinates of our current location with the geocode function.
wz <- "WZ building, AUT university"
wz_gc <- geocode(wz)
wz_gc
## lon lat
## 1 174.7668 -36.85404
Now we will create a map.
g <- qmap(location="AUT, NZ", maprange = TRUE, zoom=18,
maptype = "satellite",
base_layer = ggplot(aes(x=lon, y=lat), data = wz_gc ))
## Warning: `panel.margin` is deprecated. Please use `panel.spacing` property
## instead
g + geom_point(colour="purple", size=5)
Note: since these functions are querying google, there are some limitations in terms of maximum queries per day (2500) and per second. You may get an “OVER_QUERY_LIMIT” message. Waiting a few seconds should resolve the issue. You can check your daily limit as follows.
geocodeQueryCheck()
The get_map function is a wrapper for assorted get_* functions. Once the map has been obtained using get_map, it can be plotted using ggmap.
m <- get_map(wz_gc, zoom=14)
g <- ggmap(m)
g
The get_map function allows different map sources.
m <- get_map(wz_gc, zoom=14, source = "stamen", maptype = "watercolor")
g <- ggmap(m)
g
m <- get_map(wz_gc, zoom=14, source="google", maptype = "roadmap")
g <- ggmap(m)
g
Run the following code and notice how different “extent” options change the look of the map.
ggmap(m, extent="device")
ggmap(m, extent="normal")
ggmap(m, extent="panel")
Paths (pairs of longitudes and latitudes) can be added to plots.
# Create a random path
set.seed(500)
df <- round(data.frame(
x = jitter(rep(wz_gc$lon, 10), amount = .01),
y = jitter(rep(wz_gc$lat, 10), amount = .01)
), digits = 3)
# Create the map
map <- get_googlemap("St Pauls street, Auckland", markers = df, path = df, scale = 2, zoom=14)
# Plot the map
f <- ggmap(map, extent = 'device')
## Warning: `panel.margin` is deprecated. Please use `panel.spacing` property
## instead
f
Let us inspect the map object.
str(map)
## 'ggmap' chr [1:1280, 1:1280] "#AADAFF" "#AADAFF" "#AADAFF" "#AADAFF" ...
## - attr(*, "bb")='data.frame': 1 obs. of 4 variables:
## ..$ ll.lat: num -36.9
## ..$ ll.lon: num 175
## ..$ ur.lat: num -36.8
## ..$ ur.lon: num 175
## - attr(*, "source")= chr "google"
## - attr(*, "maptype")= chr "terrain"
## - attr(*, "zoom")= num 14
attr(map, "bb")
## ll.lat ll.lon ur.lat ur.lon
## 1 -36.87587 174.739 -36.83192 174.7939
We can colour code by a third variable.
First we load the data.
# Dummy data
citywalk <- data.frame(
lon = c(174.766, 174.767, 174.768, 174.769),
lat = c(-36.853, -36.854, -36.855, -36.856),
elevation = c(1,2,3,4)
)
Then we create the map.
citymap <- get_map(location = c(mean(citywalk$lon), mean(citywalk$lat)),
maptype = "roadmap",
source = "google",
zoom = 14)
ggmap(citymap) +
geom_path(data = citywalk, aes(color = elevation), size = 3, lineend = "round") +
scale_color_gradientn(colours = rainbow(7), breaks = seq(0, 200, by = 25))
rm(list=ls())
The final R package we will explore is leaflet.
library(leaflet)
library(rgdal)
library(rgeos)
We can create a map of our current location.
aut <- data.frame(ID = c("AUT"),
x = c(174.7664924),
y = c(-36.8539873),
group=NA)
m <- leaflet() %>%
addTiles() %>% # Add default OpenStreetMap map tiles
setView(lng = aut$x, lat = aut$y, zoom = 15)
m # Print the map
Try these functions
m %>% addMarkers(lng= aut$x, lat = aut$y, popup="WZ building")
m %>% addPopups(lng= aut$x, lat = aut$y, "Here is the <b>WZ building</b>, AUT")
rand_lng <- function(n = 10) rnorm(n, aut$x, .01)
rand_lat <- function(n = 10) rnorm(n, aut$y, .01)
# circle (units in metres)
m %>% addCircles(rand_lng(10), rand_lat(10), radius = runif(10, 50, 150))
# polyline
m %>% addPolylines(rand_lng(10), rand_lat(10))
rm(list=ls())
library(tmap)
data("World")
tmap_mode("plot")
tmap_style("watercolor")
tm_shape(World) + tm_polygons("life_exp", palette = "RdBu") +
tm_layout(bg.color = "purple", title="A title", main.title="Another title")
library(ggmap)
library(readr)
library(tidyverse)
citywalk <- read_csv("data/route_210183.csv", skip=1) # data from MapMyRun.com
citywalk <- dplyr::rename(citywalk, elevation=`elevation(meters)`)
citywalk$lat <-as.numeric(citywalk$lat)
citymap <- get_map(location = c(mean(citywalk$lon), mean(citywalk$lat)),
maptype = "roadmap",
source = "google",
zoom = 14)
ggmap(citymap) +
geom_path(data = citywalk, aes(color = elevation), size = 3, lineend = "round") +
scale_color_gradientn(colours = rainbow(7), breaks = seq(0, 200, by = 25))
locations <- data.frame(city = c("Auckland", "Taupo", "Wellington"), stringsAsFactors =FALSE)
# Get long & lat for locations
# Option 1: using geocode
# locations <- cbind(geocode(locations$city), locations)
# Option 2: using data from elsewhere
locations$lon <- c(174.7633, 176.0702, 174.7762)
locations$lat <- c(-36.84846, -38.68569, -41.28646)
summary(locations)
## city lon lat
## Length:3 Min. :174.8 Min. :-41.29
## Class :character 1st Qu.:174.8 1st Qu.:-39.99
## Mode :character Median :174.8 Median :-38.69
## Mean :175.2 Mean :-38.94
## 3rd Qu.:175.4 3rd Qu.:-37.77
## Max. :176.1 Max. :-36.85
# Create the map
map <- get_googlemap("North Island, New Zealand",
markers = locations[,c("lon", "lat")],
path = locations[,c("lon", "lat")],
scale = 2, zoom=6)
# Plot the map
f <- ggmap(map)
f
Good overview of mapping tools https://cran.r-project.org/doc/contrib/intro-spatial-rl.pdf
https://rpubs.com/nickbearman/r-google-map-making
Good introduction to the ggmap package http://stat405.had.co.nz/ggmap.pdf
More advanced information about geo-data https://geocompr.robinlovelace.net/adv-map.html
Useful overview of key R packages https://www.computerworld.com/article/2921176/business-intelligence/great-r-packages-for-data-import-wrangling-visualization.html
Rick Dalliessi, former student, provided initial Leaflet code
Tennekes M (2018). “tmap: Thematic Maps in R.” Journal of Statistical Software, 84(6), 1-39. doi: <10.18637/jss.v084.i06 (URL: http://doi.org/10.18637/jss.v084.i06)>.
D. Kahle and H. Wickham. ggmap: Spatial Visualization with ggplot2. The R Journal, 5(1), 144-161. URL http://journal.r-project.org/archive/2013-1/kahle-wickham.pdf
Joe Cheng, Bhaskar Karambelkar and Yihui Xie (2018). leaflet: Create Interactive Web Maps with the JavaScript ‘Leaflet’ Library. R package version 2.0.1. https://CRAN.R-project.org/package=leaflet